package priv.cwr.springboot.demo.model.vo.base;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.github.pagehelper.Page;
import com.google.common.base.Preconditions;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import priv.cwr.springboot.demo.component.Errors;
import priv.cwr.springboot.demo.configuration.Global;

import java.io.Serializable;
import java.util.Date;

/**
 * @author R
 * @date 2018/7/4
 * @description class Result 返回值通用接口
 */
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result<T> implements Serializable {

    private static final long serialVersionUID = -5317720079470438833L;

    @ApiModelProperty(value = "错误码", name = "错误码")
    private int code;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.sss")
    @JsonProperty("time_string")
    private Date timeString;


    private Date timestamp;

    /**
     * 发送异常的异常名称
     */
    private String exception;

    /**
     * 发生错误的跟踪id
     * 需要配置了跟踪才可以
     */
//    @JsonProperty("tracker_id")
//    private String trackerId;

    /**
     * 访问的url
     */
    private String path;
    /**
     * 返回信息，对错误码的描述
     */
    @ApiModelProperty(value = "错误码描述")
    private String message;

    /**
     * 返回数据
     */
    @ApiModelProperty(value = "数据对象", allowEmptyValue = true)
    private T data;

    /**
     * 当前页数
     */
    @ApiModelProperty(value = "分页列表数据才会有:当前页", allowEmptyValue = true)
    private Integer pageNum;

    /**
     * 总页数
     */
    @ApiModelProperty(value = "分页列表数据才会有:总页数", allowEmptyValue = true)
    private Integer pages;

    /**
     * 每页多少条
     */
    @ApiModelProperty(value = "分页列表数据才会有:每页多少条", allowEmptyValue = true)
    private Integer pageSize;

//    private int startRow;
//
//    private int endRow;

    /**
     * 总条数
     */
    @ApiModelProperty(value = "分页列表数据才会有:总条数", allowEmptyValue = true)
    private Long total;

    private int status;

    /**
     * 获取当前日期以及时间戳
     */
    private Result() {
        this.timestamp = this.timeString = new Date();
    }

    /**
     * 产生错误信息对象
     * 会去yml找枚举code对应的message，如果yml没有，直接用枚举的错误信息
     *
     * @param data       返回的对象
     * @param error      yml中配置的错误信息对象，请在controller中注入进来
     * @param errorCode  错误码
     * @param status     状态
     * @param substitute error message中需要替换的东西${index}，null代表不替换
     */
    public Result(T data, Errors error, Global.Errors globalErrors, Integer errorCode, Integer status, String... substitute) {
        this();
        String message;
        try {
            message = Preconditions.checkNotNull(error.getErrors().get(errorCode));
        } catch (NullPointerException e) {
            if (globalErrors != null) {
                message = globalErrors.getMessage();
            } else {
                message = "未配置:[" + errorCode + "]";
            }
        }
        //替换错误信息中的${*}
        try {
            for (int i = 0; i < substitute.length; i++) {
                message = message.replaceAll("\\$\\{" + i + "}", substitute[i]);
            }
        } catch (NullPointerException ignored) {
        }
        this.message = message;
        this.data = data;
        // 处理data中的分页信息
        if (data instanceof Page) {
            Page temp = (Page) data;
            this.pageNum = temp.getPageNum();
            this.pageSize = temp.getPageSize();
            this.pages = temp.getPages();
            this.total = temp.getTotal();
        }
        this.code = errorCode;
        this.status = status;
    }

    /**
     * 返回通用错误信息
     *
     * @param error        错误对象
     * @param globalErrors 错误枚举
     * @param status       请求状态
     * @param substitute   error message中需要替换的东西${index}，null代表不替换
     */
    public Result(Errors error, Global.Errors globalErrors, Integer status, String... substitute) {
        this(null, error, globalErrors, globalErrors.getCode(), status, substitute);
    }

    /**
     * 返回自定义错误信息
     *
     * @param error      错误对象
     * @param errorCode  错误码
     * @param status     请求状态
     * @param substitute error message中需要替换的东西${index}，null代表不替换
     */
    public Result(Errors error, Integer errorCode, Integer status, String... substitute) {
        this(null, error, null, errorCode, status, substitute);
    }

    /**
     * 正常返回数据
     *
     * @param data 数据对象
     */
    public Result(T data) {
        this(data, null, Global.Errors.SUCCESS, 0, 200);
    }
}
